/**
 * @brief MCU 型号规格定义头文件
 * @detail 在此头文件中定义那些与 MCU 内部具体实现有关的定义，这些定义是 mcu.h 标准的一部分，但不同的 MCU 可能取值范围有所不同。
 * @note 注意: 用户不要包含此头文件！它只由 mcu.h 包含。
 * @author 张勇 41204@qq.com
 * @date 2022-04
 */

#pragma once

#include <stm32f4xx_ll_adc.h>
#include "mcu.h"
#include "_mcu_gpio.h"

/**
 * @brief STM32F4xx ADC 输入引脚 <=> GPIO 引脚对应关系
 * @note ADC2 的输入引脚完全复用 ADC1 的引脚
 * @note ADC3 的输入引脚部分复用 ADC1/ADC2 的引脚
 * | #    | ADC1     | ADC2 | ADC3 | 说明                                 |
 * | :--: | -------- | ---- | ---- | ---                                  |
 * | IN0  | PA0      | PA0  | PA0  |                                      |
 * | IN1  | PA1      | PA1  | PA1  |                                      |
 * | IN2  | PA2      | PA2  | PA2  |                                      |
 * | IN3  | PA3      | PA3  | PA3  |                                      |
 * | IN4  | PA4      | PA4  | PF6  | ADC12_IN4 = DAC_OUT1 复用了 PA4      |
 * | IN5  | PA5      | PA5  | PF7  | ADC12_IN5 = DAC_OUT2 复用了 PA5      |
 * | IN6  | PA6      | PA6  | PF8  |                                      |
 * | IN7  | PA7      | PA7  | PF9  |                                      |
 * | IN8  | PB0      | PB0  | PF10 |                                      |
 * | IN9  | PB1      | PB1  | PF3  |                                      |
 * | IN10 |  PC0     | PC0  | PC0  |                                      |
 * | IN11 |  PC1     | PC1  | PC1  |                                      |
 * | IN12 |  PC2     | PC2  | PC2  |                                      |
 * | IN13 |  PC3     | PC3  | PC3  |                                      |
 * | IN14 |  PC4     | PC4  | PF4  |                                      |
 * | IN15 |  PC5     | PC5  | PF5  |                                      |
 * | IN16 |  MCU温度 |      |      | ADC1_IN16固定连接到MCU内部温度传感器   |
 */

// ADC 控制器数据结构
typedef struct _mcu_adc {
    ADC_TypeDef *adc;
    uint32_t chmask_init;   ///< 通道初始化状态掩码，对应位为 1 表示已经初始化
    uint32_t dma_chmask;    ///< 参与 DMA 采样的通道掩码，不应超过 chmask_init 范围
    uint32_t dma_chcount;   ///< 参与 DMA 采样的通道数量(dma_chmask 中 1 的个数)
    uint32_t dma_sampcnt;   ///< DMA 采样数据点数
    uint16_t *dma_buf;      ///< DMA 缓冲区指针, 长度为 通道数量 * 采样点数 * 采样点字节数。以3个采样通道为例，采样点排列顺序为: ch1, ch2, ch3, ch1, ch2, ch3, ...
} mcu_adc_t;


#ifdef __cplusplus
extern "C" {
#endif

/// @brief 读取 ADC 参考电压(单位: V)
float mcu_adc_read_vref();
/// @brief ADC 采样值校准(修正因参考电压偏差而导致的采样值误差)
float mcu_adc_cali(uint32_t adc_raw);
/// @brief ADC 采样值校准并转换为实际采样电压(单位: V)
float mcu_adc_cali_v(uint32_t adc_raw);
/// @brief 读取芯片内部温度(单位: C)
float mcu_adc_read_ictemp();
/// @brief 读取 VBAT 电压(单位: V)
float mcu_adc_read_vbat();

/// @brief 命名的ADC控制器定义(名字, ADC设备号, 要使用的ADC通道掩码)
/// @note 示例: ADC_DEFINE(TMPADC, ADC1, 0x07)
#define ADC_DEFINE(NAME, ADCx, CHMASK) \
    static mcu_adc_t _##NAME = {.adc = ADCx, .chmask_init = 0}; \
    mcu_adc_t *NAME = &_##NAME; \
    inline std_err_t NAME##_Init() { return mcu_adc_init(NAME, CHMASK); } \
    inline float     NAME##_Vref() { return mcu_adc_vref(NAME); } \
    inline uint32_t  NAME##_Read1(uint32_t chidx) { return mcu_adc_read1(NAME, chidx); } \
    inline std_err_t NAME##_Start(uint32_t chmask, uint8_t sample_rate, void* samples[], uint32_t sample_count, bool looping) { return mcu_adc_start(NAME, chmask, sample_rate, samples, sample_count, looping); } \
    inline std_err_t NAME##_Stop() { return mcu_adc_stop(NAME); } \
    inline std_err_t NAME##_Curr() { return mcu_adc_curr(NAME); }


#ifdef __cplusplus
} //extern "C"
#endif
